Ideam_Logo

Estaciones hidrometeorológicas


Introducción

En este cuadernillo (Notebook) aprenderemos:

  1. Introduccion a la red de monitoreo del IDEAM

  2. Cátalogo de estaciones de IDEAM

  3. Consulta de datos usando la plataforma datosabiertos.gov.co

  4. Consulta de datos de temperatura y precipitación

  5. Otros datos disponibles

Prerequisitos

Conceptos

Importancia

Notas

Introducción a Pandas

Necesario

lectura de datos tabulares

Introducción a Datetime

Necesario

Entender estampas de tiempo

Introducción a Cartopy

Necesario

Entender estampas de tiempo

Introducción a folium

Útil

Mapas interactivos

  • Tiempo de aprendizaje: 30 minutos

1. Catalogo nacional de estaciones de IDEAM

Según el catálogo de estaciones hidrometeorológicas de IDEAM, el pais cuenta con alrededor de 4.400 estaciones de diferentes categorias. En el siguiente cuadro se resume el estado de las estaciones por categoría de acuerdo a la PQR No. 20229050190832 (Enero de 2023)

Categoria

Activa

Mantenimiento

Suspendidas

Limnigráfica

287

109

106

Climátologica principal

215

60

92

Mareográfica

4

2

2

Pluviográfica

104

0

87

Limnimétrica

323

11

557

Climática Ordinaria

211

31

253

Agrometeorológica

51

4

57

Radio Sonda

6

2

2

Pluviométrica

1109

9

603

Meteorológica Especial

40

4

68

Sinóptica Principal

27

3

4

Sinóptica Secundaria

2

0

5

Total

2381

235

1866

Librerias

A continuación vamos a importar las librerias que utilizaremos en este cuadernillo

import pandas as pd
import cartopy.crs as ccrs
import cartopy.feature as feature
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
from pandas import to_datetime
from matplotlib.dates import HourLocator, DateFormatter

2. Acceso al catalogo en bart.ideam.gov.co

El catalogo nacional de estaciones de IDEAM actualizado se encuentra disponible en el servidor Bart. Podemos leer el catálogo usando pandas.read_excel como se muestra a continuación:

df_cat = pd.read_excel('http://bart.ideam.gov.co/cneideam/CNE_IDEAM.xls')
#df_cat.head()
df_cat.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4497 entries, 0 to 4496
Data columns (total 21 columns):
 #   Column                Non-Null Count  Dtype         
---  ------                --------------  -----         
 0   OBJECTID              4497 non-null   int64         
 1   CODIGO                4497 non-null   int64         
 2   nombre                4497 non-null   object        
 3   CATEGORIA             4497 non-null   object        
 4   TECNOLOGIA            4497 non-null   object        
 5   ESTADO                4497 non-null   object        
 6   FECHA_INSTALACION     4496 non-null   datetime64[ns]
 7   altitud               4497 non-null   int64         
 8   latitud               4497 non-null   float64       
 9   longitud              4497 non-null   float64       
 10  DEPARTAMENTO          4497 non-null   object        
 11  MUNICIPIO             4497 non-null   object        
 12  AREA_OPERATIVA        4497 non-null   object        
 13  AREA_HIDROGRAFICA     4497 non-null   object        
 14  ZONA_HIDROGRAFICA     4497 non-null   object        
 15  observacion           1335 non-null   object        
 16  CORRIENTE             4497 non-null   object        
 17  FECHA_SUSPENSION      1844 non-null   datetime64[ns]
 18  SUBZONA_HIDROGRAFICA  4497 non-null   object        
 19  ENTIDAD               4497 non-null   object        
 20  subred                1143 non-null   object        
dtypes: datetime64[ns](2), float64(2), int64(3), object(14)
memory usage: 737.9+ KB

2.1 Mapa de estaciones

Podemos usar cartopy para hacer un mapa y visualizar las estaciones de monitoreo en el pais

fig, ax = plt.subplots(subplot_kw={"projection": ccrs.PlateCarree()}, dpi=150)
ax.coastlines()
gl = ax.gridlines(draw_labels=True, crs=ccrs.PlateCarree())
ax.scatter(df_cat['longitud'], df_cat['latitud'], transform=ccrs.PlateCarree(), s=.5)
ax.add_feature(feature.LAND)
ax.add_feature(feature.OCEAN)
ax.add_feature(feature.COASTLINE, linewidth=.5)
ax.add_feature(feature.BORDERS, linewidth=.5)
<cartopy.mpl.feature_artist.FeatureArtist at 0x7fe89fca0510>
/usr/share/miniconda3/envs/atmoscol2023/lib/python3.11/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_land.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/usr/share/miniconda3/envs/atmoscol2023/lib/python3.11/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_ocean.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/usr/share/miniconda3/envs/atmoscol2023/lib/python3.11/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_physical/ne_50m_coastline.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
/usr/share/miniconda3/envs/atmoscol2023/lib/python3.11/site-packages/cartopy/io/__init__.py:241: DownloadWarning: Downloading: https://naturalearth.s3.amazonaws.com/50m_cultural/ne_50m_admin_0_boundary_lines_land.zip
  warnings.warn(f'Downloading: {url}', DownloadWarning)
../../_images/e224e413231bfb22b8513911359316f1d13a8f75aefe4c2beea4573892c27292.png

podemos agrupar la data por área operativa, tipo de estacion, tecnologia, y otras variables

# df_grp = df_cat.groupby('AREA_OPERATIVA')
# df_grp = df_cat.groupby('TECNOLOGIA')
df_grp = df_cat.groupby('ESTADO')
fig, ax = plt.subplots(subplot_kw={"projection":ccrs.PlateCarree()}, dpi=150)

for _, group in df_grp:
    ax.scatter(group['longitud'], group['latitud'], transform=ccrs.PlateCarree(), s=.5, label=_)
    
ax.coastlines()
gl = ax.gridlines(draw_labels=True, crs=ccrs.PlateCarree())
ax.add_feature(feature.LAND)
ax.add_feature(feature.OCEAN)
ax.add_feature(feature.COASTLINE, linewidth=.5)
ax.add_feature(feature.BORDERS, linewidth=.5)
ax.legend(fontsize=5)
<matplotlib.legend.Legend at 0x7fe8a4026290>
../../_images/8adb57003b7a4e157063c5420ec0b73c0a726f7f53655ed7c01a4bcab75c7e83.png

Podemos validar el numero total de estaciones activas, en matenimiento y suspendidas de acuerdo con la información contenida en el catálogo

for grp in df_grp.groups.keys():
    print(f"{grp}: {len(df_grp.get_group(grp))}")
Activa: 2202
En Mantenimiento: 429
Suspendida: 1866

2.2 Mapa de estaciones interactivo

También podemos hacer mapas interactivos usando folium

import folium
from folium import plugins
from folium.plugins import MarkerCluster
min_lon, max_lon, min_lat, max_lat = -90, -72, -1, 14

map_ = folium.Map(location=[8, -76],
                  zoom_start = 6, 
                  min_lat=min_lat, 
                  max_lat=max_lat, 
                  min_lon=min_lon, 
                  max_lon=max_lon, 
                  zoom_control=False,
                  control_scale=True,
                  scrollWheelZoom=True,
                  width=1000,height=600)
marker_cluster = MarkerCluster(name="Estaciones").add_to(map_)

folium.TileLayer('cartodbpositron').add_to(map_)
folium.TileLayer('openstreetmap').add_to(map_)
folium.TileLayer('stamenterrain').add_to(map_)
folium.TileLayer('cartodbdark_matter').add_to(map_)
folium.LayerControl().add_to(map_)

minimap = plugins.MiniMap()
_ = map_.add_child(minimap)
# _

Ahora agregamos las estaciones usando la siguiente función

def plot_station(row):
    '''input: series that contains a numeric named latitude and a numeric named longitude
    this function creates a CircleMarker and adds it to your this_map'''
    
    html = row.to_frame("_").to_html(classes="table table-striped table-hover table-condensed table-responsive")
    popup = folium.Popup(html, max_width=2650)
    folium.Marker(location=[row.latitud, row.longitud], popup=popup).add_to(marker_cluster)
df_cat.apply(plot_station, axis=1)
map_
Make this Notebook Trusted to load map: File -> Trust Notebook

3. Acceso a la información historica de IDEAM usando datosabiertos.gov.co

la información historica de multiples sensores se puede consultar atraves de la plataforma de datos abiertos usando el aplicativo sodapy. Socrata utiliza un módulo denominado Socrata que permite realizar consultas al repositorio. Cada variable hidrometeorógica dispuesta se puede consultar usando el su respectivo código del set de datos.

Variable

Código del set de datos

Dirección del viento

kiw7-v9ta

Nivel instantaneo

bdmn-sqnh

Temperatura Minima del Aire

afdg-3zpb

Temperatura Maxima del Aire

ccvq-rp9s

Velocidad del Viento

sgfv-3yp8

Nivel Maximo

vfth-yucv

Nivel Minimo

pt9a-aamx

Humedad del Aire

uext-mhny

Temperatura

sbwg-7ju4

Nivel del mar mínimo

7z6g-yx9q

Nivel del mar máximo

uxy3-jchf

Nivel del mar

ia8x-22em

Presión Atmosferica

62tk-nxj5

Precipitación

s54a-sgyg

# importamos la libreria Socrata
from sodapy import Socrata

3.1 Precipitación (s54a-sgyg)

Vamos a consultar los datos de precipitación reportada en la página. por ende vamos a usar el código s54a-sgyg. Para esto usamos el metodo Socrata, pasamos la direccion del repositorio y None que corresponde a la no autenticación

# conexión cliente usando socrata al repositorio de datos abiertos
client = Socrata("www.datos.gov.co", None)
WARNING:root:Requests made without an app_token will be subject to strict throttling limits.

Una vez creado el cliente empezamos a hacer la consulta de datos usando client.get y pasando los respectivos parámetros dataset_identifier, de la tabla anterior , y limit para generar consultas no muy grandes para efectos demostrativos. El resultado es una lista con multiples diccionarios como se puede ver a continuación.

# Solicitud de informacion al repositorio de interés
results = client.get(dataset_identifier="s54a-sgyg", limit=2000)
results[:1]
[{'codigoestacion': '0023085270',
  'codigosensor': '0240',
  'fechaobservacion': '2018-04-02T05:30:00.000',
  'valorobservado': '0',
  'nombreestacion': 'APTO J.M CORDOVA TX GPRS',
  'departamento': 'ANTIOQUIA',
  'municipio': 'RIONEGRO',
  'zonahidrografica': 'MEDIO MAGDALENA',
  'latitud': '6.169',
  'longitud': '-75.426',
  'descripcionsensor': 'Precipitacion',
  'unidadmedida': 'mm'}]

Estos resultados los podemos convertir en un Dataframe usando pandas.Dataframe.from_records

results_df = pd.DataFrame.from_records(results)
results_df.head()
codigoestacion codigosensor fechaobservacion valorobservado nombreestacion departamento municipio zonahidrografica latitud longitud descripcionsensor unidadmedida
0 0023085270 0240 2018-04-02T05:30:00.000 0 APTO J.M CORDOVA TX GPRS ANTIOQUIA RIONEGRO MEDIO MAGDALENA 6.169 -75.426 Precipitacion mm
1 0021202180 0240 2016-04-17T03:05:00.000 0 QUIBA - FOPAE BOGOTA D.C. BOGOTA, D.C ALTO MAGDALENA 4.543 -74.156 Precipitacion mm
2 0021257120 0240 2013-02-16T23:40:00.000 0 PUENTE NEGRO - AUT TOLIMA VILLAHERMOSA ALTO MAGDALENA 4.940194444 -75.08980556 Precipitacion mm
3 0011037030 0240 2013-11-05T13:40:00.000 0 LA LOMA PUEBLO NUEVO - En Siniestro CHOCÓ RIO QUITO (PAIMADÓ) ATRATO - DARIÉN 5.585 -76.753 Precipitacion mm
4 0021202170 0240 2010-12-26T07:30:00.000 0 SIERRA MORENA - FOPAE BOGOTA D.C. BOGOTA, D.C ALTO MAGDALENA 4.567 -74.167 Precipitacion mm

Ahora podemos usar filtrar los datos por diferentes campos como el codigoestacion, fechaobservacion, o valorobservado. Podemos pasar parametros SQL como where, AND, IN, entre otros, en el método client.get

# client.get?
# Solicitud de informacion para la estación de la Universidad Nacional - Bogotá - 0021205012
ppt_query = client.get(dataset_identifier="s54a-sgyg", 
                       select="fechaobservacion, valorobservado, codigoestacion", 
                       where="codigoestacion IN ('0021205012') \
                              AND fechaobservacion > '2017'")
df_est = pd.DataFrame.from_records(ppt_query)
df_est.head()
fechaobservacion valorobservado codigoestacion
0 2017-06-15T01:00:00.000 0 0021205012
1 2018-07-04T13:20:00.000 0 0021205012
2 2019-08-16T05:50:00.000 0 0021205012
3 2017-01-13T11:30:00.000 0 0021205012
4 2017-08-31T14:40:00.000 0 0021205012

Gráfico de la serie temporal

Podemos generar una serie temporal usando la información resultado de la consulta. Sin embargo, primero debemos revisar el tipo de dato de cada columna

df_est.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000 entries, 0 to 999
Data columns (total 3 columns):
 #   Column            Non-Null Count  Dtype 
---  ------            --------------  ----- 
 0   fechaobservacion  1000 non-null   object
 1   valorobservado    1000 non-null   object
 2   codigoestacion    1000 non-null   object
dtypes: object(3)
memory usage: 23.6+ KB
df_est['fechaobservacion'] = pd.to_datetime(df_est['fechaobservacion'])
df_est.set_index('fechaobservacion', inplace=True)
df_est.valorobservado = df_est['valorobservado'].astype(float)
df_est = df_est.sort_index()
df_est.tail()
valorobservado codigoestacion
fechaobservacion
2019-08-24 08:50:00 0.0 0021205012
2019-08-26 11:30:00 0.0 0021205012
2019-08-26 14:00:00 0.0 0021205012
2019-08-27 16:00:00 0.0 0021205012
2019-08-27 19:20:00 0.0 0021205012
# pd.options.plotting.backend = 'holoviews'
fig, ax = plt.subplots(figsize=(12, 3))
df_est['valorobservado'].plot(ax=ax, drawstyle="steps")
<Axes: xlabel='fechaobservacion'>
../../_images/fec9e9bcf237fe29e3bd052000372ae84f529036dde4a73486bcc1bf5feeaef5.png

Podemos solicitar informacion para estaciones que reportan datos en el último més

ppt_query = client.get(dataset_identifier="s54a-sgyg", 
                       select="fechaobservacion, valorobservado, codigoestacion, nombreestacion", 
                       where="fechaobservacion > '2023-09-11'")
df_ult = pd.DataFrame.from_records(ppt_query)
df_ult.head()
fechaobservacion valorobservado codigoestacion nombreestacion
0 2023-09-11T00:01:00.000 0 3502500135 GUAYABETAL POLLO OLIMPICO - AUT
1 2023-09-11T00:03:00.000 0 3502500135 GUAYABETAL POLLO OLIMPICO - AUT
2 2023-09-11T00:04:00.000 0 3502500135 GUAYABETAL POLLO OLIMPICO - AUT
3 2023-09-11T00:05:00.000 0 0026177030 LA VIRGINIA
4 2023-09-11T00:05:00.000 0 3502500135 GUAYABETAL POLLO OLIMPICO - AUT

3.2 Temperatura (sbwg-7ju4)

De manera similar podemos consultar otros registros como los de temperatura. Cambiamos el identificador de set de datos y generamos una nueva consulta

# Solicitud de informacion para la estación de la Universidad Nacional - Bogotá - 0021205012
temp_query = client.get(dataset_identifier="sbwg-7ju4", 
                       select="fechaobservacion, valorobservado, codigoestacion", 
                       where="codigoestacion IN ('0021205012') \
                              AND fechaobservacion > '2017'")
df_temp = pd.DataFrame.from_records(temp_query)
df_temp.index = pd.to_datetime(df_temp['fechaobservacion'])
df_temp.valorobservado = df_temp['valorobservado'].astype(float)
df_temp = df_temp.sort_index()
df_temp.tail()
fechaobservacion valorobservado codigoestacion
fechaobservacion
2020-01-22 08:00:00 2020-01-22T08:00:00.000 13.6 0021205012
2020-01-22 10:00:00 2020-01-22T10:00:00.000 18.1 0021205012
2020-01-22 12:00:00 2020-01-22T12:00:00.000 17.6 0021205012
2020-01-22 16:00:00 2020-01-22T16:00:00.000 17.7 0021205012
2020-01-22 21:00:00 2020-01-22T21:00:00.000 13.8 0021205012
fig, ax = plt.subplots(figsize=(12, 3))
df_temp['valorobservado'].plot(c='C00', lw=0.5, ax=ax)
<Axes: xlabel='fechaobservacion'>
../../_images/c9d32fa9be82de501ac6d7880231454dff857a2fa7b16a5db68fc7a26825bab1.png

4. Datos en tiempo “Causireal” de IDEAM

De igual manera, el Ideam dispone de una tabla de datos en tiempo cercano a la medición. Esta tabla corresponde al dataset_identifier="57sv-p2fu". Generemos una consulta básica para ver los campos contenidos dentro de esta tabla en el último día

time_now = datetime.now()
time = time_now - timedelta(days=1)
time
datetime.datetime(2023, 10, 12, 20, 16, 13, 58590)

Convertimos la fecha en un str para incluirlo en la consulta

time_str = f"{to_datetime(time):%Y-%m-%d}"
time_str
'2023-10-12'
nrt_query = client.get(dataset_identifier="57sv-p2fu", 
                        select="*", 
                        where="fechaobservacion >= '{}'".format(time_str),
                        limit=2000)
df_nrt = pd.DataFrame.from_records(nrt_query)
df_nrt.head()
codigoestacion codigosensor fechaobservacion valorobservado nombreestacion departamento municipio zonahidrografica latitud longitud descripcionsensor unidadmedida entidad
0 0017015010 0028 2023-10-13T02:02:00.000 86 AEROPUERTO SESQUICENTENARIO ARCHIPIÉLAGO DE SAN ANDRES PROVIDENCIA Y SANTA... SAN ANDRÉS ISLAS CARIBE 12.587849 -81.701117 GPRS - HUMEDAD DEL AIRE A 2 m % INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
1 0023085270 0028 2023-10-12T18:40:00.000 75 AEROPUERTO J.M. CORDOVA ANTIOQUIA RIONEGRO MEDIO MAGDALENA 6.1686111 -75.42611111 GPRS - HUMEDAD DEL AIRE A 2 m % INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
2 0021125010 0069 2023-10-12T14:13:00.000 31 SANTA MARIA HUILA SANTA MARÍA ALTO MAGDALENA 2.93569444 -75.58905556 TEMPERATURA DEL AIRE MÁXIMA A 2 m °C INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
3 0025025240 0103 2023-10-12T23:50:00.000 0.2 MAJAGUAL SUCRE MAJAGUAL BAJO MAGDALENA- CAUCA -SAN JORGE 8.54269444 -74.62733306 VELOCIDAD DEL VIENTO m/s INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
4 0013035501 0257 2023-10-12T22:04:00.000 0 AEROPUERTO LOS GARZONES CÓRDOBA MONTERÍA SINÚ 8.82583333 -75.82513889 GPRS - PRECIPITACIÓN mm INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...

Los primeros registros nos indican que hay mediciones cercanas a las fechas de la ejecución de este cuadernillo. Generemos una consulta más específica para la estacion 0024035340 correspindiente al Aeropuerto Alberto Lleras Camargo de Sogamoso.

cod_est = '0024035340'
aero_query = client.get(dataset_identifier="57sv-p2fu", 
                        select="*", 
                        where="fechaobservacion >= '{}'\
                        AND codigoestacion IN ('{}')".format(time_str, cod_est),
                        limit=2000)
df_aero = pd.DataFrame.from_records(aero_query)
df_aero.head(10)
codigoestacion codigosensor fechaobservacion valorobservado nombreestacion departamento municipio zonahidrografica latitud longitud descripcionsensor unidadmedida entidad
0 0024035340 0258 2023-10-13T01:30:00.000 759.3 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - PRESIÓN ATMOSFÉRICA hPA INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
1 0024035340 0258 2023-10-12T16:28:00.000 756.8 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - PRESIÓN ATMOSFÉRICA hPA INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
2 0024035340 0111 2023-10-12T15:18:00.000 4.8 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - VELOCIDAD DEL VIENTO m/s INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
3 0024035340 0071 2023-10-13T00:58:00.000 6.7 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - TEMPERATURA DEL AIRE A 2 m °C INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
4 0024035340 0257 2023-10-13T03:04:00.000 0 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - PRECIPITACIÓN mm INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
5 0024035340 0240 2023-10-13T00:10:00.000 0 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 PRECIPITACIÓN mm INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
6 0024035340 0111 2023-10-12T16:30:00.000 6.4 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - VELOCIDAD DEL VIENTO m/s INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
7 0024035340 0028 2023-10-13T01:32:00.000 100 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - HUMEDAD DEL AIRE A 2 m % INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
8 0024035340 0111 2023-10-12T21:58:00.000 0.8 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - VELOCIDAD DEL VIENTO m/s INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...
9 0024035340 0258 2023-10-12T20:20:00.000 759.3 AEROPUERTO A LLERAS C BOYACÁ SOGAMOSO SOGAMOSO 5.67694444 -72.96791667 GPRS - PRESIÓN ATMOSFÉRICA hPA INSTITUTO DE HIDROLOGIA METEOROLOGIA Y ESTUDIO...

Para validar los sensores que tiene esta estacion podemo usar el método .unique() de Pandas

df_aero.codigosensor.unique()
array(['0258', '0111', '0071', '0257', '0240', '0028', '0255', '0104',
       '0027', '0103', '0068', '0069', '0070'], dtype=object)

Podemos centrar aún mas la consulta agregandole el sensor de temperatura codigosensor=0071

cod_sensor = '0071'
aero_query = client.get(dataset_identifier="57sv-p2fu", 
                        select="fechaobservacion, valorobservado", 
                        where="fechaobservacion >= '{}'\
                        AND codigoestacion IN ('{}') \
                        AND codigosensor IN ('{}')".format(time_str, cod_est, cod_sensor),
                        limit=2000)
df_aero = pd.DataFrame.from_records(aero_query)
df_aero
fechaobservacion valorobservado
0 2023-10-13T00:58:00.000 6.7
1 2023-10-12T22:16:00.000 8.9
2 2023-10-12T18:02:00.000 15.9
3 2023-10-13T01:10:00.000 4.7
4 2023-10-13T01:28:00.000 4.7
... ... ...
711 2023-10-13T15:06:00.000 21.4
712 2023-10-13T15:08:00.000 21.3
713 2023-10-13T15:10:00.000 21
714 2023-10-13T15:12:00.000 20.7
715 2023-10-13T15:14:00.000 20.6

716 rows × 2 columns

Ahora generemos un gráfico rápido de la serie de temperatura para las ultimas 24 horas

fig, ax = plt.subplots(figsize=(10, 3))
df_aero.index = pd.to_datetime(df_aero['fechaobservacion'])
df_aero.valorobservado = df_aero['valorobservado'].astype(float)
df_aero.plot(ax=ax)
ax.xaxis.set_major_locator(HourLocator(interval=4)) # tick every four hours
ax.xaxis.set_major_formatter(DateFormatter('%m-%d\n%H:%M'))
../../_images/f40ce9480bb33f3c19b407fd0a576d5f8654905eff4949928599c8062c3081fd.png

Conclusiones

En este cuadernillo aprendimos una manera fácil y rápida para acceder a la información histórica y presente de las estaciones hidrometeorológicas de IDEAM. De igual modo aprendimos a visualizar las estaciones usando mapas interactivos. También aprendimos a generar consultas a diferentes grupos de datos usando sintaxis SQL y el aplicativo socrata de la plataforma de datos abiertos del gobierno colombiano.

Resources and references

  • Rose, B. E. J., Kent, J., Tyle, K., Clyne, J., Banihirwe, A., Camron, D., May, R., Grover, M., Ford, R. R., Paul, K., Morley, J., Eroglu, O., Kailyn, L., & Zacharias, A. (2023). Pythia Foundations (Version v2023.05.01) https://doi.org/10.5281/zenodo.7884572